#pragma once

#include <unordered_map>
#include "Connector.h"
#include "Handler.h"
#include "Define.h"
#include "ThreadPool.h"

namespace wsbus {

	class NodeImpl
	{
	public:
		NodeImpl(int appId, const std::string &host, const std::string &port);
		~NodeImpl();

		void setAuth(const std::string &username, const std::string &password);
		void setHeartbeatInterval(int second);
		void start();
		ConnStatus status() const { return status_; }

		PackagePtr newRequestPackage(const MessagePtr &msg, int toAppType, int toSessionId = 0);
		PackagePtr newRequestPackage(const std::string &command, const std::string &data, int toAppType, int toSessionId = 0);
		int sendMessage(const PackagePtr &reqMsg, PackagePtr &rspMsg, int msTimeout = 10000);
		int postMessage(const PackagePtr &msg, const HandleMessage &cb, int msTimeout = 10000);
		int pushMessage(const MessagePtr &msg);
		int replyMessage(const PackagePtr &reqPackage, const MoreMessagePtr &rspMsg);

		void addRequestHandler(const std::string &cmd, const std::function<MoreMessagePtr(const PackagePtr&)> &cb);
		void addPublishHandler(const std::string &cmd, const std::function<void(const PackagePtr)> &cb);
		void setStatusChangedHandler(const std::function<void(int status)> &cb);

	private:
		void postPackage(const PackagePtr &msg);
		void setStatus(ConnStatus status);
		void onConnect();
		void onRead(const BufferPtr &msg);
		void onConnectorConnected(bool connected);
		void onConnectorError(int error);

		void login();
		void doHeartbeat(const boost::system::error_code &e);
		void startHeartbeatTimer();

	private:
		int appType_;
		int sessionId_;
		std::string host_;
		std::string port_;
		std::string username_;
		std::string password_;
		ConnStatus status_;
		int reconnectCount_;
		Connector connector_;
		ResponseHandler responseHandler_;
		RequestHandler requestHandler_;
		PublishHandler publishHandler_;
		std::function<void(int)> statusChangedHandler_;
		std::mutex syncMsgMutex_;
		std::condition_variable syncMsgCond_;
		ThreadPool requestThreadTool_;
		int heartbeatSeconds_;
		std::unique_ptr<boost::asio::deadline_timer> heartbeatTimer_;
	};

}